package cn.tedu.charging.order.job;

import cn.tedu.charging.common.pojo.param.GunStatusUpdateParam;
import cn.tedu.charging.order.config.SpringContextJobUtil;
import cn.tedu.charging.order.constant.Constant;
import cn.tedu.charging.order.dao.repository.OrderRepository;
import cn.tedu.charging.order.feign.DeviceClient;
import cn.tedu.charging.order.pojo.po.ChargingBillFailPO;
import cn.tedu.charging.order.pojo.po.ChargingBillSuccessPO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.UUID;

/**
 * https://zhuanlan.zhihu.com/p/564387885
 * 设备自检定时任务 尽快的发现设备故障
 * 如果没有这个定时任务,设备出现了故障,走到死信队列 时间会很长
 * 2分钟自检时间
 * 故障  charging_bill_fail 查一条记录 故障原因 设备无响应
 * 正常 charging_bill_success 更新 订单相关的信息(更新gunId)
 * todo 要做持久化 xxl-job 分布式任务
 * 定时任务 1 按照设置的固定的频率 2 干一些事情
 */


/**
 * 设备自检定时任务
 * 定时任务 1 按照设置的固定的频率 2 干一些事情
 */
@Slf4j
public class DeviceCheckJob implements Job {

    /**
     * 必须无参的构造器
     * 如果没有,在初始化的时候 newInstance 通过getConstructor0 获取构造器来初始化
     * NoSuchMethodException 找不到方法 找不到默认构造器
     */
    public DeviceCheckJob() {}

    /**
     * 设置固定频率
     */
    public DeviceCheckJob(String orderNo,Integer gunId) throws Exception {
        log.debug("添加设备自检定时任务:{}",orderNo);
        //创建调度器工厂
        StdSchedulerFactory factory = new StdSchedulerFactory();
        //通过调度器工厂获取调度器
        Scheduler scheduler = factory.getScheduler();

        //创建定时任务
        JobDetail jobDetail = JobBuilder.newJob(DeviceCheckJob.class)
                //定义定时任务的名称和组
                .withIdentity("DeviceCheckJob" + UUID.randomUUID(),"device_check_job")
                //传入订单号
                .usingJobData("orderNo",orderNo)
                .usingJobData("gunId",gunId)
                //构建
                .build();

        //当前时间
        long now = System.currentTimeMillis();
        //设备自检需要1分钟
        long deviceCheckTime = now + 1 * 60 * 1000;
        //任务触发的时间
        Date triggerTime = new Date(now + deviceCheckTime);
        //创建触发器 并 设置时间
        Trigger trigger = TriggerBuilder.newTrigger()
                .startAt(triggerTime)
                .build();

        //定时任务和触发器绑定到调度
        scheduler.scheduleJob(jobDetail,trigger);

        //启动调度器
        scheduler.start();
    }


    /**
     * 干一些事情
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.debug("任务开始执行:{}",context);
        //任务开始执行后 业务该如何处理
        //startCharging
        //1 设备接收到了充电指令,返回了开始充电成功指令 成功订单表有数据
        //2 设备接收到了充电指令,返回了开始充电失败指令 失败订单表有数据
        //3 没有收到任何设备返回的信息, 成功订单表没数据  失败订单表没数据  设备无响应
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        log.debug("JobDataMap:{}",jobDataMap);
        String orderNo = jobDataMap.getString("orderNo");
        int gunId = jobDataMap.getInt("gunId");

        OrderRepository orderRepository = (OrderRepository)SpringContextJobUtil.getBean("orderRepository");

        //判断订单成功表中有没有数据
        ChargingBillSuccessPO chargingBillSuccessPO = orderRepository.getSuccess(orderNo);
        if(chargingBillSuccessPO == null){
            //没有成功订单数据
            //判断订单失败表中有没有数据
            ChargingBillFailPO chargingBillFailPO = orderRepository.getFail(orderNo);
            if(chargingBillFailPO == null){
                //没有失败订单数据
                ChargingBillFailPO chargingBillFailPO1 = new ChargingBillFailPO();
                chargingBillFailPO1.setBillId(orderNo);
                chargingBillFailPO1.setFailDesc("设备无响应");
                orderRepository.saveFailOrder(chargingBillFailPO1);
            }else {
                log.debug("订单失败表中有数据:{}",chargingBillFailPO);
                //如果有失败订单有记录 设备失败是 "设备自检失败-设备有响应但是充不了电"
                //这的逻辑无需 把设备失败的原因 改为  "设备无响应"
            }
            //成功没有数据 设备故障了 更改设备状态
            GunStatusUpdateParam updateParam = new GunStatusUpdateParam();
            updateParam.setStatus(Constant.GUN_STATS_ERROR);
        }else {
            //有成功的订单数据 --完善订单数据的操作
            // 把用户id,枪id,运营商id,车辆id,充电站id 更新到订单表
            orderRepository.updateSuccessOrder(orderNo,gunId);
        }
    }
}
